package com.example.video.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.video.entity.Account;
import com.example.video.entity.Video;
import com.example.video.Enum.videoStatus;
import com.example.video.common.Result;
import com.example.video.entity.ResponseData;
import com.example.video.mapper.AccountMapper;
import com.example.video.mapper.VideoMapper;
import com.example.video.service.IVideoService;
import com.example.video.util.download.DownTask;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author qiusuyang
 * @since 2024-04-13
 */
@Slf4j
@Service
public class VideoServiceImpl implements IVideoService {

    @Value("${downLoadPath}")
    private String downLoadPath;
    @Resource
    private VideoMapper mapper;
    @Resource
    private DownTask downTask;
    @Resource
    private  AccountServiceImpl accountService;
    @Resource
    private VideoLogServiceImpl videoLogService;
    @Resource
    private AccountMapper accountMapper;

    @Override
    public boolean updateStatusByid(Integer videoId, Integer status){
        return mapper.update(new UpdateWrapper<Video>()
                .eq("id", videoId)
                .set("status", status)
        ) > 0;
    }

    @Override
    public List<Video> getList(Integer page, Integer size ){
        QueryWrapper<Video> qwrapper = new QueryWrapper<>();
        IPage<Video> iPage = mapper.selectPage(new Page<>(page,size),qwrapper);
        return iPage.getRecords();
    }

    /**
     * 批量处理视频，先获取视频所属的账户，然后与数据中的视频信息进行比较，如果有则不处理，没有则插入。
     * 插入后就进行下载视频操纵，创建下载线程。
     * @param data 解析出来的资源数据
     * @param accountId 源账户id
     * @return
     */
    @Override
    public boolean addList(ResponseData.Data data, Integer accountId, String next_cursor,Authentication authentication){

        boolean down_flag = false;

        Account account  = accountService.getItem(accountId);
        Integer total = account.getTotal();
//        log.info("VideoSerImpl -> addList -> msg : account = "+account);
        // 遍历数据库中的数据，若已有数据就不进行插入。若无则进行插入，并进行下载视频操作。
        // 若在视频错误log中有数据，则重新下载该数据
//        List<VideoLog> videoLogs = videoLogService.getAll();
        for ( int i =0; i<data.getPosts().size(); i++) {
            ResponseData.Post post = data.getPosts().get(i);
            // 若无id
            // 5.5 快手、b站的资源url中，最后一个/后的资源可能为资源id，使用这个   4.30 新增 若无id则创建一个id
            // eg. 快手： http://111.67.199.184:8123/video/goto/1714815866406.mp4?sign=nnuV-ofv9VN2Rjz2QbPiDpOlPmPWf
            // b站: http://upos-sz-mirror08c.bilivideo.com/upgcxcode/48/75/1525307548/1525307548-1-192.mp4?e=ig8eux
            if(post.getId() == null || "".equals(post.getId()) ){
                // 5.5 注释，换成使用资源url里的id
                // post.setId(MD5Utils.encryptMD5(account.getUrl() + next_cursor + i + post.getText() )) ;
                String url = post.getMedias().get(0).getResource_url();
                int lastSlashIndex = url.lastIndexOf('/');
                String extractedString = url.substring(lastSlashIndex + 1, url.lastIndexOf('.'));
                post.setId(extractedString);
            }else{
                // 如果 url 为Instagram，则判断是否有 _ 有就去掉下划线和下划线后的。
                if( account.getUrl().contains("instagram") && post.getId().contains("_") ){
                    post.setId( post.getId().split("_")[0] );
                }
            }

            Video video = mapper.selectOne(new QueryWrapper<Video>()
                    .eq("resource_id",post.getId())
                    .eq("account_id",account.getId())
            );

            // 若数据库有数据，则不插入
            if(video != null ){
//                System.out.print("VideoSerImpl -> addList -> msg : 已有数据：");
                if(video.getStatus() == videoStatus.UNDOWNLOADING.getStatus() ){
//                    log.info("VideoSerImpl -> addList -> msg :  未下载，再次下载 ："+post.getId());
                    downTask.addTask(post, account, next_cursor);
                    total --;
                } else{
//                    log.info(post.getId() + "\t已下载，不进行插入");
                    total --;
                }
                down_flag = true;
            }else{
//                log.info("VideoSerImpl -> addList -> msg : 插入数据库："+post.getId());
                downTask.addTask(post, account, next_cursor);
//                down_flag = false;
            }
        }

        // 如果此次的cursor请求的数据中，数据库已有过数据，则将account的next_cursor设置为null，从头开始
        if(down_flag){
            account.setNextCursor("");
        }
        account.setTotal(total);
//        log.info("VideoSerImpl -> addList -> msg :aft  account = "+account);
        accountService.updateById(account);
        return true;
    }

    /**
     * 根据账户id获取该账户下的视频
     * @param userId 账户id
     * @return
     */
    @Override
    public List<Video> getListByAccountId(Integer userId){
        return mapper.selectList(new QueryWrapper<Video>()
                .eq("account_id",userId)
        );
    }
    @Override
    public List<Video> getListByRole(String role){
        return mapper.selectList(new QueryWrapper<Video>().eq("role",role));
    }

    /**
     * 根据账户id和状态获取该账户下的视频
     * @param page 分页
     * @param size 大小
     * @param idList 账户id数组
     * @param downLoading 视频状态
     * @param authentication 认证
     * @return 视频列表
     */
    @Override
    public List<Video> getListByAccountIdAndStatus(Integer page, Integer size, List<Integer> idList, Integer status){
        QueryWrapper<Video> qwrapper = new QueryWrapper<>();

        qwrapper.eq("status", status)
                // ??????
//                .eq("role",roles)
                .in("account_id",idList);

        IPage<Video> iPage = mapper.selectPage(new Page<>(page,size),qwrapper);


        return iPage.getRecords();
    }

    /**
     * 获取下载状态的视频信息
     * @param accountId 账户id
     * @param status 视频状态
     * @return
     */
    @Override
    public Video getItemByAccountIdAndStatus(Integer accountId,  videoStatus status) {
        // 创建分页对象，只查询第一页，每页只返回一条记录
        Page<Video> page = new Page<>(1, 1);

        // 创建查询条件
        QueryWrapper<Video> queryWrapper = new QueryWrapper<Video>()
                .eq("account_id", accountId)
                .eq("status", status.getStatus())
                .orderByAsc("id");

        // 执行分页查询
        Page<Video> resultPage = mapper.selectPage(page, queryWrapper);

        // 获取结果，如果有数据返回第一个记录，否则返回 null
        if (resultPage.getRecords().isEmpty()) {
            return null;
        } else {
            return resultPage.getRecords().get(0);
        }
    }

    /**
     * 根据id获取视频信息
     * @param id
     * @return
     */
    @Override
    public Video getItem(Integer id){
        return mapper.selectById(id);
    }

    /**
     * 插入视频信息
     * @param item
     * @return
     */
    @Override
    public boolean save(Video item){
        Video video = mapper.selectOne(new QueryWrapper<Video>()
                .eq("resource_id",item.getResourceId())
        );
        boolean flag ;
//        若该资源id不存在存在
        if( video == null ){
            log.info("videoImpl -> item -> msg：资源不存在！");
            flag = mapper.insert(item) > 0;
        }else{
            log.info("videoImpl -> item -> msg：资源已存在，进行更新！");
            item.setId(video.getId());
            flag = mapper.updateById(item) > 0;
        }
        return flag;
    }

    /**
     * 通过id删除视频信息
     * TODO ，并删除对应的本地视频
     * @param id
     * @return
     */
    @Override
    public boolean delete(Integer id){
        return mapper.deleteById(id) > 0 ;
    }




    /**
     * 获取视频总数，给layui分页使用
     * @return
     */
    @Override
    public long getCount() {
        return mapper.selectCount(new QueryWrapper<Video>());
    }

    /**
     * 根据账户id获取该账户下的视频总数
     * @param accountId
     * @return
     */
    @Override
    public long getCountByAccountId(Integer accountId) {
        return mapper.selectCount(new QueryWrapper<Video>()
                .eq("account_id",accountId)
                .eq("status",videoStatus.DOWNLOADING.getStatus())
        );

    }

    @Override
    public Video getItemByResourceIdAndAccountId(String resourceId, Integer accountId) {
        return mapper.selectOne(new QueryWrapper<Video>()
                .eq("resource_id",resourceId)
                .eq("account_id",accountId)
        );
    }

    @Override
    public List<Video> getListByNotDownLoading() {

        return mapper.selectList(new QueryWrapper<Video>()
                .select("account_id","err_cursor")
                .eq("status", videoStatus.UNDOWNLOADING.getStatus())
        );

    }

    @Override
    public List<Video> getListByNotDownLoadingAndAccountIdArr(List<Integer> idList) {
        return mapper.selectList(new QueryWrapper<Video>()
                .select("account_id","err_cursor")
                .eq("status",videoStatus.UNDOWNLOADING.getStatus())
                .in("account_id",idList)
        );
    }

    @Override
    public long getCountByAccountIdAndDownLoading(List<Integer> accountIdList, Integer downLoading) {
        return mapper.selectCount(new QueryWrapper<Video>()
                .eq("status",downLoading)
                .in("account_id",accountIdList)
        );
    }

    @Override
    public Result<List<Integer>> status(Account account) {
        Result<List<Integer>> rs = new Result<>();
        QueryWrapper<Video> wrapper = new QueryWrapper<>();
        wrapper
                .eq("account_id",account.getId())
                .eq("status",videoStatus.DOWNLOADING.getStatus());
        //查这个账号的没下载完的视频对象
        List<Video> videos = mapper.selectList(wrapper);
        if (videos.isEmpty()){
            rs.setCode(-1);
            rs.setMsg("没有新视频");
            rs.setData(null);
            return rs;
        }
        //抽出新视频的id
        List<Integer> videoIds = videos.stream().map(Video::getId).collect(Collectors.toList());
        //设置响应对象
        rs.setCode(0);
        rs.setMsg("有新视频");
        rs.setCount(videoIds.size());
        rs.setData(videoIds);
        return rs;
    }
}
